﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
//using YArchitech.BIM.XRouter;
using HYRevitCode.ShortPathSuite;
using YArchitech.Revit;
using YArchitech.Revit.Electric.Common;
using HYElectricSetting;

namespace YArchitech.MEP.Electric.CableLay
{
	internal class AutomaticLaying
	{
		public AutomaticLaying(Document doc, CableListData data)
		{
			this.doc = doc;
			this.data = data;
		}

		public CableListData Laying()
		{
			this.ClearDataResultField();
			Element equipmentByNumber = CableLayRevitCommon.GetEquipmentByNumber(this.doc, this.data.StartNum);
			Element equipmentByNumber2 = CableLayRevitCommon.GetEquipmentByNumber(this.doc, this.data.EndNum);
			if (equipmentByNumber == null || equipmentByNumber2 == null)
			{
				this.data.Remark = "未找到起点或终点设备";
				return this.data;
			}
			if (!CableLayRevitCommon.CableTraySchemaDataRemove(this.doc, this.data))
			{
				this.data.Remark = "清除敷设数据异常";
				return this.data;
			}
			this.FindConnectionEquipment(equipmentByNumber);
			List<ElementId> source;
			List<XYZ> lstVertex;
			RouteResult routeResult;
			this.ShortestPathLaying(equipmentByNumber, equipmentByNumber2, out source, out lstVertex, out routeResult);
			if (routeResult != RouteResult.eOK)
			{
				this.data.Remark = "无效的桥架系统";
				return this.data;
			}
			if (CableLayCommon.IsApplyCableLayRule())
			{
				this.RemoveTrayWithoutCondition();
				this.ShortestPathLaying(equipmentByNumber, equipmentByNumber2, out source, out lstVertex, out routeResult);
				if (routeResult != RouteResult.eOK)
				{
					this.data.Remark = "不符合容积率要求";
					return this.data;
				}
			}
			List<ElementId> lstEdge = source.Distinct<ElementId>().ToList<ElementId>();
			Transaction transaction = new Transaction(this.doc, "WriteCableData");
			try
			{
				transaction.Start();
				this.WriteCableData(this.data, lstEdge, lstVertex);
				transaction.Commit();
			}
			catch
			{
				this.data.Remark = "写入敷设数据异常";
				return this.data;
			}
			finally
			{
				if (transaction != null && (int)transaction.GetStatus() != 3)
				{
					transaction.RollBack();
				}
			}
			this.data.Remark = "敷设完成";
			return this.data;
		}

		private void ClearDataResultField()
		{
			this.data.Length = string.Empty;
			this.data.LayPath = string.Empty;
			this.data.LayPathIDs = string.Empty;
			this.data.Remark = string.Empty;
		}

		private void WriteCableData(CableListData data, List<ElementId> lstEdge, List<XYZ> lstVertex)
		{
			foreach (ElementId elementId in lstEdge)
			{
				Element elementById = this.doc.GetElementById(elementId);
				List<CableTraySchemaData> list = new List<CableTraySchemaData>();
				CableTraySchemaDataManager.GetData(elementById, ref list);
				CableTraySchemaData item = new CableTraySchemaData
				{
					CableNumber = data.CableNum,
					Model = data.CableModel,
					Spec = data.CableSpec,
					Section = Math.PI * Math.Pow(CableDatabase.ThisDb.GetOutDiameter(data.CableModel, data.CableSpec) / 2.0, 2.0)
				};
				list.Add(item);
				CableTraySchemaDataManager.SetData(elementById, list);
			}
			List<double> list2 = new List<double>();
			for (int i = 0; i < lstVertex.Count - 1; i++)
			{
				double length = (lstVertex[i + 1] - lstVertex[i]).GetLength();
				list2.Add(length);
			}
			data.Length = (AssistFunc.feetToMM(list2.Sum()) / 1000.0).ToString("0.00");
			string text = "";
			foreach (ElementId elementId2 in lstEdge)
			{
				Element element = this.doc.GetElement(elementId2);
				if (element is CableTray)
				{
					Parameter parameter = element.GetParameter("编号");
					if (parameter == null)
					{
						text = text + element.Id + ",";
					}
					else
					{
						string text2 = parameter.AsString();
						if (string.IsNullOrEmpty(text2))
						{
							text = text + element.Id + ",";
						}
						else
						{
							text = text + text2 + ",";
						}
					}
				}
			}
			data.LayPath = ((text == "") ? "" : text.Substring(0, text.LastIndexOf(",")));
			string text3 = "";
			foreach (ElementId elementId3 in lstEdge)
			{
				text3 = text3 + elementId3.ToString() + ",";
			}
			data.LayPathIDs = ((text3 == "") ? "" : text3.Substring(0, text3.LastIndexOf(",")));
		}

		private void ShortestPathLaying(Element startDevice, Element endDevice, out List<ElementId> lstEdge, out List<XYZ> lstVertex, out RouteResult result)
		{
			this.edges.Clear();
			this.AnalysisElementEdge();
			UndirectGraph undirectGraph = new UndirectGraph();
			foreach (ShortPathEdge shortPathEdge in this.edges)
			{
				undirectGraph.AddEdge(shortPathEdge.StartPt, shortPathEdge.EndPt, shortPathEdge.ElementId);
			}
			XYZ devicePoint = this.GetDevicePoint(startDevice);
			XYZ devicePoint2 = this.GetDevicePoint(endDevice);
			ShortestPath shortestPath = new ShortestPath(undirectGraph);
			result = shortestPath.RouteShortestPath(devicePoint, devicePoint2, out lstEdge, out lstVertex);
		}

		private void RemoveTrayWithoutCondition()
		{
			List<Element> list = new List<Element>();
			foreach (Element element in this.allEquipment)
			{
				if (element is CableTray)
				{
					CableTray cableTray = element as CableTray;
					if (!this.IsMeetVolumeRatio(cableTray))
					{
						list.Add(cableTray);
					}
				}
			}
			foreach (Element item in list)
			{
				this.allEquipment.Remove(item);
			}
		}

		private bool IsMeetVolumeRatio(CableTray cableTray)
		{
			bool result = false;
			double num = CableLayCommon.VolumeRatioOfSystemType(cableTray.GetParameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).AsString());
			if (num == 0.0)
			{
				return true;
			}
			double num2 = 0.0;
            double num3 = (double)Convert.ToInt16(UnitConvert.CovertFromAPI((DisplayUnitType)2, cableTray.Width));
            int num4 = (int)Convert.ToInt16(UnitConvert.CovertFromAPI((DisplayUnitType)2, cableTray.Height));
			num2 = num3 * (double)num4;
			double num5 = 0.0;
			List<CableTraySchemaData> list = new List<CableTraySchemaData>();
			if (!CableTraySchemaDataManager.GetData(cableTray, ref list))
			{
				num5 = 0.0;
			}
			else
			{
				foreach (CableTraySchemaData cableTraySchemaData in list)
				{
					num5 += cableTraySchemaData.Section;
				}
			}
			double num6 = Math.PI * Math.Pow(CableDatabase.ThisDb.GetOutDiameter(this.data.CableModel, this.data.CableSpec) / 2.0, 2.0);
			num5 += num6;
			if (num5 / num2 < num)
			{
				result = true;
			}
			return result;
		}

		private void FindConnectionEquipment(Element device)
		{
			foreach (Element device2 in this.GetConnectedEquipment(device))
			{
				this.FindConnectionEquipment(device2);
			}
		}

		private List<Element> GetConnectedEquipment(Element element)
		{
			List<Connector> connectorList = new List<Connector>();
			List<Element> list = new List<Element>();
			if (element is CableTray)
			{
				connectorList = RevitUtils.GetCableTrayConnectors(element as CableTray);
			}
			else if (element is Conduit)
			{
				connectorList = RevitUtils.GetConduitConnectors(element as Conduit);
			}
			else if (element is FamilyInstance)
			{
				connectorList = RevitUtils.GetConduitFittingConnectors(element);
			}
			foreach (Element element2 in AutomaticLayingCommon.GetEquipmentByConnectors(connectorList))
			{
				if (!this.allEquipment.Contains(element2, this.equipmentComparer))
				{
					this.allEquipment.Add(element2);
					list.Add(element2);
				}
			}
			return list;
		}

		private void AnalysisElementEdge()
		{
			foreach (Element element in this.allEquipment)
			{
				if (element is Conduit || element is CableTray)
				{
					MEPCurve mepCurve = element as MEPCurve;
					this.StructureCableLayLine(mepCurve);
				}
			}
		}

		private void StructureCableLayLine(MEPCurve mepCurve)
		{
			List<Connector> list = new List<Connector>();
			Curve curve = (mepCurve.Location as LocationCurve).Curve;
			XYZ endPoint = curve.GetEndPoint(0);
			XYZ endPoint2 = curve.GetEndPoint(1);
			if (mepCurve is Conduit)
			{
				list = RevitUtils.GetConduitConnectors(mepCurve as Conduit);
			}
			else if (mepCurve is CableTray)
			{
				list = RevitUtils.GetCableTrayConnectors(mepCurve as CableTray);
			}
			Connector connector = null;
			Connector connector2 = null;
			foreach (Connector connector3 in list)
			{
				if (connector3.Origin.IsAlmostEqualTo(endPoint))
				{
					connector = connector3;
				}
				if (connector3.Origin.IsAlmostEqualTo(endPoint2))
				{
					connector2 = connector3;
				}
			}
			if (list.Count > 2)
			{
				FamilyInstance equipmentByMEPCurveConnector = AutomaticLayingCommon.GetEquipmentByMEPCurveConnector(connector);
				FamilyInstance equipmentByMEPCurveConnector2 = AutomaticLayingCommon.GetEquipmentByMEPCurveConnector(connector2);
				List<XYZ> ls = new List<XYZ>();
				if (equipmentByMEPCurveConnector != null)
				{
					XYZ deviceConnPoint = this.GetDeviceConnPoint(mepCurve, equipmentByMEPCurveConnector);
					if (deviceConnPoint != null)
					{
						ls.Add(deviceConnPoint);
					}
				}
				if (equipmentByMEPCurveConnector2 != null)
				{
					XYZ deviceConnPoint = this.GetDeviceConnPoint(mepCurve, equipmentByMEPCurveConnector2);
					if (deviceConnPoint != null)
					{
						ls.Add(deviceConnPoint);
					}
				}
				list.Remove(connector);
				list.Remove(connector2);
				foreach (Connector connector4 in list)
				{
					ls.Add(connector4.Origin);
				}
				List<XYZ> list2 = (from c in ls
				orderby c.DistanceTo(ls[0])
				select c).ToList<XYZ>();
				for (int i = 0; i < list2.Count - 1; i++)
				{
					this.AddEdge(list2[i], list2[i + 1], mepCurve.Id);
				}
				return;
			}
			XYZ startPt = endPoint;
			XYZ endPt = endPoint2;
			FamilyInstance equipmentByMEPCurveConnector3 = AutomaticLayingCommon.GetEquipmentByMEPCurveConnector(connector);
			FamilyInstance equipmentByMEPCurveConnector4 = AutomaticLayingCommon.GetEquipmentByMEPCurveConnector(connector2);
			if (equipmentByMEPCurveConnector3 != null)
			{
				XYZ deviceConnPoint2 = this.GetDeviceConnPoint(mepCurve, equipmentByMEPCurveConnector3);
				if (deviceConnPoint2 != null)
				{
					startPt = deviceConnPoint2;
				}
			}
			if (equipmentByMEPCurveConnector4 != null)
			{
				XYZ deviceConnPoint2 = this.GetDeviceConnPoint(mepCurve, equipmentByMEPCurveConnector4);
				if (deviceConnPoint2 != null)
				{
					endPt = deviceConnPoint2;
				}
			}
			this.AddEdge(startPt, endPt, mepCurve.Id);
		}

		private XYZ GetDeviceConnPoint(MEPCurve mepCurve, FamilyInstance startDevice)
		{
			XYZ xyz = null;
			int integerValue = startDevice.Category.Id.IntegerValue;
			if (integerValue != -2008126 && integerValue != -2008128)
			{
				Dictionary<Connector, MEPCurve> mepcurveByConnectors = AutomaticLayingCommon.GetMEPCurveByConnectors(RevitUtils.GetCableTrayConduitConnector(startDevice));
				if (mepcurveByConnectors.Count > 0)
				{
					xyz = mepcurveByConnectors.Keys.First<Connector>().Origin;
				}
			}
			else
			{
				int num = startDevice.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE).AsInteger();
				if (num == 39 || num == 40 || num == 47 || num == 48 || num == 7 || num == 13)
				{
					xyz = this.GetPoint(mepCurve, startDevice);
					if (xyz == null)
					{
						xyz = (startDevice.Location as LocationPoint).Point;
					}
				}
				else
				{
					xyz = (startDevice.Location as LocationPoint).Point;
				}
			}
			return xyz;
		}

		private XYZ GetPoint(Element mepCurve, FamilyInstance startDevice)
		{
			XYZ result = null;
			FamilyInstance familyInstance = null;
			List<Connector> conduitFittingConnectors = RevitUtils.GetConduitFittingConnectors(startDevice);
			FamilyInstance equipmentByConnectors = this.GetEquipmentByConnectors(mepCurve, conduitFittingConnectors, ref familyInstance);
			if (familyInstance != null)
			{
				return (familyInstance.Location as LocationPoint).Point;
			}
			if (equipmentByConnectors != null)
			{
				result = this.GetPoint(startDevice, equipmentByConnectors);
			}
			return result;
		}

		public FamilyInstance GetEquipmentByConnectors(Element mepCurve, List<Connector> connectorList, ref FamilyInstance instance)
		{
			FamilyInstance result = null;
			foreach (Connector connector in connectorList)
			{
				ConnectorSet allRefs = connector.AllRefs;
				if (allRefs.Size > 0)
				{
					foreach (object obj in allRefs)
					{
						Element owner = ((Connector)obj).Owner;
						if (owner.Id.IntegerValue != mepCurve.Id.IntegerValue && owner is FamilyInstance)
						{
							FamilyInstance familyInstance = owner as FamilyInstance;
							if (familyInstance.Category.Id.IntegerValue == -2008126 || familyInstance.Category.Id.IntegerValue == -2008128)
							{
								int num = familyInstance.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE).AsInteger();
								if (num == 39 || num == 40 || num == 47 || num == 48 || num == 7 || num == 13)
								{
									result = familyInstance;
								}
								else
								{
									instance = familyInstance;
								}
							}
						}
					}
				}
			}
			return result;
		}

		private void AddEdge(XYZ startPt, XYZ endPt, ElementId elementId)
		{
			ShortPathEdge item = new ShortPathEdge(startPt, endPt, elementId);
			this.edges.Add(item);
		}

		private XYZ GetDevicePoint(Element element)
		{
			XYZ result = null;
			if (!(element is FamilyInstance))
			{
				return result;
			}
			Dictionary<Connector, MEPCurve> mepcurveByConnectors = AutomaticLayingCommon.GetMEPCurveByConnectors(RevitUtils.GetCableTrayConduitConnector(element as FamilyInstance));
			bool flag = false;
			foreach (KeyValuePair<Connector, MEPCurve> keyValuePair in mepcurveByConnectors)
			{
				ElementId id = keyValuePair.Value.Id;
				using (List<ShortPathEdge>.Enumerator enumerator2 = this.edges.GetEnumerator())
				{
					while (enumerator2.MoveNext())
					{
						if (enumerator2.Current.ElementId.IntegerValue == id.IntegerValue)
						{
							result = keyValuePair.Key.Origin;
							flag = true;
							break;
						}
					}
				}
				if (flag)
				{
					break;
				}
			}
			return result;
		}

		private Document doc;

		private EquipmentComparer equipmentComparer = new EquipmentComparer();

		private CableListData data = new CableListData();

		private List<Element> allEquipment = new List<Element>();

		private List<ShortPathEdge> edges = new List<ShortPathEdge>();
	}
}
